#!/usr/bin/env python
# -*- mode: python; coding: utf-8; -*-
##--------------------------------------------------------------------------##
##
## Copyright (C) 1998-2003 Markus Oberhumer <markus@oberhumer.com>
## Copyright (C) 2003 Mt. Hood Playing Card Co.
## Copyright (C) 2005-2010 Skomoroh <skomoroh@users.sourceforge.net>
## Copyright (C) 2010-2013 Jeremy Austin-Bardo <tjaustinbardo@gmail.com>
##
## This program is free software: you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
## the Free Software Foundation, either version 3 of the License.
##
## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
## GNU General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with this program.  If not, see <http://www.gnu.org/licenses/>.
##
##-- G34 -- S14 ------------------------------------------------------------##
__all__ = []

from .. import comparecards as cmp_cards
from .. import formlib as layout
from .. import pilelib as stack
from .. import quickplayscore as quickplay
from .. import stackfill as fill
from ..forms import (fortythieves as FortyThievesLayout, gypsy as GypsyLayout,
                     freecell as FreeCellLayout, klondike as KlondikeLayout,)
from ..gamelib import info as gi, game, state
from ..packlib import info as cs, place
from ..pilelib import move as a_move
from ..piles import spider, yukon
from ..utillib.misc import kwdefault

GT, SL = gi.GT, gi.SL
Wrap = stack.StackWrapper


class Irmgard_Talon(stack.DealRowTalon):
    """
    Deal 1 card on _row_. Last deal 1 card on [1:8] _row.
    """

    @property
    def _piles(self):
        """
        _piles -> tup

        :return: deal Game.s.rows until last then Game.s.rows [1:8]
        :rtype: tuple
        """
        return (self.game.s['rows'] if len(self.cards) > 7
                                 else self.game.s['rows'][1:8])


class DealRowFoundationTalon(stack.DealRowTalon):
    """
    all Aces go to Foundations
    """

    def dealToStacks(self, stacks, **kw):
        """
        dealToStacks(stacks:tup [, flip:bool=True, reverse:bool=False,
          frames:int=-1]) -> int

        Deal cards to each stack or finish ACE on foundation.

        :keyword tuple stacks: piles recieving a card
        :keyword boolean flip: open card ?
        :keyword boolean reverse: reverse pile order?
        :keyword boolean sound: sound fx?
        :return: number cards dealt
        :rtype: integer
        """
        return self.deal_row_or_drop(stack, ncards=cs.MAX, **kw)


class Bad7Talon(stack.DealRowRedealTalon):

    def dealToStacks(self, stacks, **kw):
        """
        dealToStacks(stacks:tup [, flip:bool=True, reverse:bool=False,
          frames:int=-1]) -> int

        Deal cards to each stack or finish ACE on foundation.

        :keyword tuple stacks: piles recieving a card
        :keyword boolean flip: open card ?
        :keyword boolean reverse: reverse pile order?
        :keyword boolean sound: sound fx?
        :return: number cards dealt
        :rtype: integer
        """
        return self.deal_row_or_drop(stack, ncards=cs.MAX, **kw)

    def deal_cards(self, rows=None, shuffle=False, sound=False, reverse=False,
                  **kw):
        """
        deal_cards([sound:bool=False, shuffle=False, reverse=False]) -> int

        Actual dealing, called from game.talon_deal(). Overide default, to
        allow cards to be dealt a set to and redealt from _piles alt open.

        :keyword boolean sound: sound fx?
        :keyword boolean shuffle: shuffle cards before redealing?
        :keyword boolean reverse: deals cards in reverse order?
        :return: number of cards dealt.
        """
        if self.cards:
            return super(Bad7Talon, self).deal_cards(sound=sound)
        ncards = 0
        game = self.game
        if sound and game.can_play_sound:
            game._play_sound('deal')
        ncards += self._redeal(rows=self._piles, frames=4)
        if shuffle:
            game._move_do(a_move.AShuffleStackMove(self, game.random)
                          )  # low level
        if reverse:
            self.cards.reverse()
        game._move_do(a_move.ANextRoundMove(self), reset=True)  # low level
        nrows = len(self._piles)
        flip = not (ncards / nrows) & 1
        while self.cards:
            flip = len(self.cards) <= nrows or not flip
            self.dealRow(flip=flip)
        return ncards


class Cone_Talon(stack.DealRowTalon):

    @property
    def _piles(self):
        """
        _piles -> tup

        :return: deal Game.s.reserves
        :rtype: tuple
        """
        return (self.game.s['rows'] if len(self.cards) > 4
                                 else self.game.s['reserve'])

    def can_deal_cards(self):
        """
        can_deal_cards() -> bool

        Usually informs via game.can_deal_cards() if pile can deal more
        cards. Default is to not allow dealing.

        :return: deal more cards?
        :rtype: True | False
        """
        if not super(Cone_Talon, self).can_deal_cards():
            return False
        return len(self.cards) == 4 or all(bool(r.cards) for r in self._piles)


class RightTriangle_Talon(stack.FaceUp_StackMethods, stack.OpenDragMethods,
                          stack.DealRowTalon):
    _BOTTOM_IMAGE_ = 'shade'

    def __init__(self, x, y, game, **cap):
        """
        __init__(x:int, y:int, game:obj[, offset:tup=(0, 0), *talon*
          {max_rounds:int=1, num_deal:int=1}, *capability* {max_move=1}]) ->
          None

        :param integer x: left x-coordinate.
        :param integer y: top y-coordinate.
        :param object game: current Game.
        :keyword tuple offset: offset from left top per card on pile.

        seealso::
          Module pysollib.stackcaps with details of *capability* keywords.

          Class pysollib.stack.Talon for *talon* keywords
        """
        kwdefault(cap, max_move=1, max_accept=1, max_cards=cs.MAX)
        super(RightTriangle, self).__init__(x, y, game, **cap)

    def _dealHandler(self, event):
        """
        _dealHandler(event:obj) -> bool

        Handler to allow a subclass easy access to deal a card.

        :param object event: canvas event.
        :return: event state
        :rtype: True | False | None
        """
        return super(RightTriangle, self).clickHander(event)

    def _playHandler(self, event):
        """
        _playHandler(event:obj) -> bool

        Handler to allow a subclass easy access to play a card.

        :param object event: canvas event.
        :return: event state
        :rtype: True | False | None
        """
        flip = self.game._autopiles(event)[0]
        if self in flip and self.cardFlips():
            self.game.flip(self)
            return True
        return False

    def clickHandler(self, event):
        """
        clickHandler(event:obj) -> bool

        A <left-click> will deal cards if can_deal_cards(), otherwise will play
        cards.

        :param object event: canvas event.
        :return: event state
        :rtype: True | False | None
        """
        if self.cards and not self.TOPCARD.face_up:
            return self._dealHandler
        return self._playHandler

    def can_deal_cards(self):
        """
        can_deal_cards() -> bool

        Usually informs via game.can_deal_cards() if pile can deal more
        cards. Default is to allow dealing when cards and not open.

        :return: deal more cards?
        :rtype: True | False
        """
        if not super(RightTriangle, self).can_deal_cards(self):
            return False
        return self.cards and not self.TOPCARD.face_up

    def cardFlips(self):
        """
        cardFlips() -> bool

        Check if pile can flip face down top card. The default is not to flip.

        :return: pile flips top card?
        :rtype: boolean
        :raises: AssertionError: Class is not root class method.
        """
        return False


class Trapdoor_Talon(stack.DealReserveTalon):

    def deal_cards(self, sound=False):
        """
        deal_cards([sound:bool=False, shuffle=False]) -> None

        Actual dealing, called from game.talon_deal(). Overide default, to
        play cards from _reserve_ to neighbor _row_ then deal _piles.

        :keyword boolean sound: sound fx?
        :keyword boolean shuffle: shuffle cards before redealing?
        """
        if not self.cards:
            return 0
        rows, reserves = self.game.s['rows'], self.game.s['reserves']
        assert len(rows) == len(reserves)
        if sound:
            self.game._play_sound('deal')
        n = 0
        for row, reserve in zip(rows, reserves):
            if reserve.cards:
                reserve.move_pile(1, row)
                n += 1
        n += super(Trapdoor_Talon, self).deal_cards(self, sound=False)
        return n


class Giant_Foundation(stack.EmptyTalonBuildMethod,
                       stack.SS_Foundation):
    pass


class DieRussische_Foundation(stack.AbstractFoundation):

    def isSequence(self, cards):
        """
        _sequence(cards:seq) -> bool

        :param sequence cards: cards from sending pile
        :return: accept card sequence acccording to *capabilities*?
        :rtype: boolean
        """
        return cmp_cards.isSequenceWithRanks(cards, self.game['ranks'],
                                             **self.cap)


class LockedCards_Foundation(stack.SS_Foundation):

    def isSequence(self, cards):
        """
        _sequence(cards:seq) -> bool

        :param sequence cards: cards from sending pile
        :return: accept card sequence acccording to *capabilities*?
        :rtype: boolean
        """
        if not super(LockedCards_Foundation, self).isSequence(cards):
            return False
        return not self.cards or cmp_cards.isSameSuit(self.cards[-1:] + cards)


class DieRussische_RowStack(stack.GapTopBuildMethod, stack.AC_RowStack):
    pass


class MissMilligan_ReserveStack(stack.EmptyTalonBuildMethod,
                                stack.AC_RowStack):
    """
    Build seq down in rank by alt color after _talon_ and pile are gaps.
    """
    _BOTTOM_IMAGE_ = 'shade'

    def cardsBuild(self, from_stack, cards):
        """
        cardsBuild(from_stack:obj, cards:seq) -> bool

        Check parent.cardsBuild() and cards isSequence() with top card
        acccording to *capabilities*.

        :param object from_stack: sending pile
        :param sequence cards: cards from sending pile
        :return: pile accepts ``cards``?
        :rtype: boolean
        """
        if not super(MissMilligan_ReserveStack, self).cardsBuild(from_stack,
                                                                 cards):
            return False
        return not self.cards


class Surprise_ReserveStack(stack.EmptyTalonBuildMethod,
                            stack.ReserveStack):
    pass


class Leprechaun_Reserve(stack.OpenStack):

    def cardFlips(self):
        """
        cardFlips() -> bool

        Check if pile can flip face down top card. The default is not to flip
        until neighbor _foundation_ has cards.

        :return: pile flips top card?
        :rtype: boolean
        """
        if not super(Leprechaun_Reserve, self).cardFlips():
            return False
        i = self.game.s['reserves'].index(self)
        return self.game.s['foundations'][i].cards


class LockedCards_Reserve(stack.OpenStack):

    def cardFlips(self):
        """
        cardFlips() -> bool

        Check if pile can flip face down top card. The default is not to flip
        until _foundation_ has is filled.

        :return: pile flips top card?
        :rtype: boolean
        """
        if not super(LockedCards_Reserve, self).canFlipCard():
            return False
        i = list(self.game.s['reserves']).index(self)
        return self.game.s['foundations'][i].is_filled


class Gypsy(game.Game):
    """
    Finish cards on _foundation_ within 1 turn.

    :CVariables:
      _layout_ : pysollib.layout.Layout
        .. pysollib.layouts.gypsy.GypsyLayout
        - row [8 horz NW, vert offset]
        - talon [1 SE, no offset]
        - foundation [8 over 2 col E, no offset]

    _row_
      Init deal 3 card. Build down in rank by alt color. Play
      seq.

    _talon_
      Deal 1 card on _row_.

    _foundation_
      Build up in rank by same suit. Play top.
    ------
    :cvar Stack _talon_: stack.DealRowTalon
    :cvar Stack _waste_: None
    :cvar Stack _foundation_: stack.SS_Foundation
    :cvar Stack _row_: stack.AC_RowStack
    :cvar Hint _hint_: hint.DefaultHint
    """
    __info__ = dict(id=1, name='Gypsy', game_type=(GT.GYPSY | GT.POPULAR |
                    GT.ATARI | GT.GNOME | GT.KDE | GT.XPAT), decks=2,
                    skill_level=SL.MOSTLY_SKILL, version='1.00')
    __author__ = 'Markus Oberhumer'
    __version__ = 7.70

    _layout_ = GypsyLayout.GypsyLayout
    _talon_ = stack.DealRowTalon
    _waste_ = None
    _foundation_ = stack.SS_Foundation
    _row_ = stack.AC_RowStack

    def _create_game(self, **kw):
        kwdefault(kw, rows=8, texts=True)
        return super(Gypsy, self)._create_game(**kw)

    def _start(self, rows=3, flip=False, **kw):
        """
        Deal initial cards for new game.
          - s[rows] 3 ea top.

        .. \_start([rows=3, flip=False]) -> None
        """
        for i in range(rows - 1):
            self.s['talon'].dealRow(flip=flip, frames=0)
        self.s['talon'].dealRow()


class Giant(Gypsy):
    """
    Finish cards on _foundation_ within 1 turn.

    :CVariables:
      _layout_ : pysollib.layout.Layout
        .. pysollib.layouts.gypsy.GypsyLayout
        - row [8 horz NW, vert offset]
        - talon [1 SE, no offset]
        - foundation [8 over 2 col E, no offset]

    _row_
      Init deal 1 card. Build down in rank by alt color. Play
      seq.

    _talon_
      Deal 1 card on _row_.

    _foundation_
      Build up in rank by same suit. Play top.
    ------
    :cvar Stack _talon_: stack.DealRowTalon
    :cvar Stack _waste_: None
    :cvar Stack _foundation_: stack.SS_Foundation
    :cvar Stack _row_: stack.AC_RowStack
    :cvar Hint _hint_: hint.DefaultHint
    """
    __info__ = dict(id=65, name='Giant', game_type=GT.GYPSY, decks=2,
                    skill_level=SL.MOSTLY_SKILL, version='3.00')
    __author__ = 'Markus Oberhumer'
    __version__ = 7.70

    _foundation_ = Giant_Foundation

    def _start(self, rows=1, **kw):
        """
        Deal initial cards for new game.
          - s[rows] 1..lEN//2..1 top.

        .. \_start([rows=1, flip=False]) -> None
        """
        super(Giant, self)._start(rows=rows, **kw)


class Irmgard(Gypsy):
    """
    Finish cards on _foundation_ within 1 turn.

    _row_
      Pile 9 horz N. Init deal [1..5..1] card. Build down in rank by alt
      color. Play seq. Base KING.

    _talon_
      Pile 1 SE. Deal 1 card on _row_. Last deal 1 card on [2..8] _row.

    _foundation_
      Pile 8 horz S. Build up in rank by same suit. Play top.
    ------
    :cvar Layout _layout_: layout.HarpLayout
    :cvar Stack _talon_: Irmgard_Talon
    :cvar Stack _waste_: None
    :cvar Stack _foundation_: stack.SS_Foundation
    :cvar Stack _row_: stack.AC_RowStack (base_rank=KING)
    :cvar Hint _hint_: hint.DefaultHint
    """
    __info__ = dict(id=3, name='Irmgard', game_type=(GT.GYPSY |
                    GT.ATARI), decks=2,
                    skill_level=SL.MOSTLY_SKILL, version='1.00')
    __author__ = 'Markus Oberhumer'
    __version__ = 7.70

    _layout_ = layout.HarpLayout
    _talon_ = Irmgard_Talon
    _row_ = Wrap(stack.AC_RowStack, base_rank=cs.KING)

    def _create_game(self, **kw):
        kwdefault(kw, rows=9, playcards=19)
        return super(Irmgard, self)._create_game(**kw)

    def _start(self, flip=False, **kw):
        """
        Deal initial cards for new game.
          - s[rows] 1..lEN//2..1 top.

        .. \_start([flip=False]) -> None
        """
        nrows = len(self.s['rows'])
        for i in range(1, int(nrows / 2) + 1):
            self.s['talon'].dealRow(rows=self.s['rows'][i:nrows - i], flip=flip,
                                    frames=0)
        self.s['talon'].dealRow()


class DieKoenigsbergerin(Gypsy):
    """
    Finish cards on _foundation_ within 1 turn.

    :CVariables:
      _layout_ : pysollib.layout.Layout
        .. pysollib.layouts.gypsy.GypsyLayout
        - row [8 horz NW, vert offset]
        - talon [1 SE, no offset]
        - foundation [8 over 2 col E, no offset]

    _row_
      Init deal 3 open card. Build down in rank by alt color.
      Play seq.

    _talon_
      Deal 1 card on _row_. Finish ACE on _foundation_.

    _foundation_
      Build up in rank by same suit. Play none.
    ------
    :cvar Stack _talon_: DealRowFoundationTalon
    :cvar Stack _waste_: None
    :cvar Stack _foundation_: stack.SS_Foundation (max_move=0)
    :cvar Stack _row_: stack.AC_RowStack
    :cvar Hint _hint_: hint.DefaultHint
    """
    __info__ = dict(id=119, name='Die Königsbergerin', game_type=GT.GYPSY,
                    decks=2, skill_level=SL.MOSTLY_SKILL,
                    version='3.10')
    __author__ = 'Markus Oberhumer'
    __version__ = 7.70

    _talon_ = DealRowFoundationTalon
    _foundation_ = Wrap(stack.SS_Foundation, max_move=0)

    def _start(self, flip=True, **kw):
        """
        Deal initial cards for new game.
          - s[rows] 1 ea up.

        .. \_start([rows=3, flip=true]) -> None
        """
        super(DieKoenigsbergerin, self)._start(flip=flip, **kw)


class DieRussische(Gypsy):
    """
    Finish cards on _foundation_ within 1 turn.

    :CVariables:
      _layout_ : pysollib.layout.Layout
        .. pysollib.layouts.gypsy.GypsyLayout
        - row [7 horz NW, vert offset]
        - talon [1 SE, no offset]
        - foundation [8 over 2 col E, no offset]

    _row_
      Init deal 3 card. Build down in rank by alt color. Play
      seq.

    _talon_
      Deal 1 card on _row_.

    _foundation_
      Init deal 1 base ACE. Build up in rank by same
      suit. Play top.
    ------
    :cvar Stack _talon_: stack.InitialDealTalon
    :cvar Stack _waste_: None
    :cvar Stack _foundation_: DieRussische_Foundation, (min_cards=1)
    :cvar Stack _row_: DieRussische_RowStack
    :cvar Hint _hint_: hint.DefaultHint
    """
    __info__ = dict(id=174, name='Russian Patience', game_type=(GT.TWO_DECK |
                    GT.OPEN), decks=2, skill_level=SL.MOSTLY_SKILL,
                    altnames=('Die Russische',), version='4.20',
                    ranks=cs.SHORT_A7K)
    __author__ = 'Markus Oberhumer'
    __version__ = 7.70

    _talon_ = stack.InitialDealTalon
    _foundation_ = Wrap(DieRussische_Foundation, min_cards=1)
    _row_ = DieRussische_RowStack

    def _create_game(self, **kw):
        kwdefault(kw, rows=7, texts=False)
        return super(DieRussische, self)._create_game(**kw)

    def _pack_place(self, cards):
        """
        _pack_place(cards:seq(Card ...)) -> seq(Card ...)

        Overide to return single ACE on bottom for _foundation_ deal.
        """
        return place.MoveToBottom(cards, place.AllAce, ncards=1)

    def _start(self, rows=9, flip=True, **kw):
        """
        Deal initial cards for new game.
          - s[rows] 9 ea up.
          - s[foundations] 1 base.

        .. \_start([rows=9, flip=true]) -> None
        """
        for i in range(rows - 1):
            self.s['talon'].dealRow(flip=flip, frames=0)
        self.s['talon'].dealRow()
        self.s['talon'].dealBaseCards(ncards=1, saveinfo=False)


class MissMilligan(Gypsy):
    """
    Finish cards on _foundation_ within 1 turn.

    _row_
      Pile 8 horz S _foundation_. Init deal 1 card. Build down in rank by alt
      color. Play seq. Base KING.

    _reserve_
      Pile 1 W. Build 1 seq down in rank by alt color after _talon_ gap.
      Play seq.

    _talon_
      Pile 1 NW. Deal 1 card on _row_.

    _foundation_
      Pile 8 horz N. Build up in rank by same suit. Play none.
    ------
    :cvar Layout _layout_: layout.MilliganLayout
    :cvar Stack _talon_: stack.DealRowTalon
    :cvar Stack _waste_: None
    :cvar Stack _foundation_: stack.SS_Foundation (max_move=0)
    :cvar Stack _row_: stack.AC_RowStack (base_rank=KING)
    :cvar Stack _reserve_: MissMilligan_ReserveStack
    :cvar Hint _hint_: hint.DefaultHint
    """
    __info__ = dict(id=62, name='Miss Milligan', game_type=GT.GYPSY, decks=2,
                    skill_level=SL.MOSTLY_SKILL, version='3.00')
    __author__ = 'Markus Oberhumer'
    __version__ = 7.70

    _layout_ = layout.MilliganLayout
    _foundation_ = Wrap(stack.SS_Foundation, max_move=0)
    _row_ = Wrap(stack.AC_RowStack, base_rank=cs.KING)
    _reserve_ = MissMilligan_ReserveStack

    def _create_game(self, **kw):
        kwdefault(kw, rows=8, reserves=1)
        return super(MissMilligan, self)._create_game(**kw)

    def _start(self, rows=1, **kw):
        """
        Deal initial cards for new game.
          - s[rows] 1 ea.

        .. \_start([rows=1, flip=False]) -> None
        """
        return super(MissMilligan, self)._start(rows=rows, **kw)


class ImperialGuards(MissMilligan):
    """
    Finish cards on _foundation_ within 1 turn.

    _row_
      Pile 8 horz S _foundation_. Init deal 1 card. Build down in rank by alt
      color. Play seq.

    _reserve_
      Pile 1 W. Build 1 seq down in rank by alt color after _talon_ gap.
      Play seq.

    _talon_
      Pile 1 NW. Deal 1 card on _row_.

    _foundation_
      Pile 8 horz N. Build up in rank by same suit. Play none.
    ------
    :cvar Layout _layout_: layout.MilliganLayout
    :cvar Stack _talon_: stack.DealRowTalon
    :cvar Stack _waste_: None
    :cvar Stack _foundation_: stack.SS_Foundation (max_move=0)
    :cvar Stack _row_: stack.AC_RowStack
    :cvar Stack _reserve_: MissMilligan_ReserveStack
    :cvar Hint _hint_: hint.DefaultHint
    """
    __info__ = dict(id=486, name='Imperial Guards', game_type=GT.GYPSY,
                    decks=2, skill_level=SL.MOSTLY_SKILL,
                    version='0.93fc')
    __author__ = 'Skomoroh'
    __version__ = 7.70

    _row_ = stack.AC_RowStack


class Nomad(ImperialGuards):
    """
    Finish cards on _foundation_ within 1 turn.

    _row_
      Pile 8 horz S _foundation_. Init deal 4 card. Build down in rank by alt
      color. Play seq.

    _reserve_
      Pile 1 W. Build any 1 card. Play top.

    _talon_
      Pile 1 NW. Deal 1 card on _row_.

    _foundation_
      Pile 8 horz N. Build up in rank by same suit. Play top.
    ------
    :cvar Layout _layout_: layout.MilliganLayout
    :cvar Stack _talon_: stack.DealRowTalon
    :cvar Stack _waste_: None
    :cvar Stack _foundation_: stack.SS_Foundation
    :cvar Stack _row_: stack.AC_RowStack
    :cvar Stack _reserve_: stack.ReserveStack
    :cvar Hint _hint_: hint.DefaultHint
    """
    __info__ = dict(id=200, name='Nomad', game_type=(GT.GYPSY | GT.CONTRIB |
                    GT.ORIGINAL | GT.GNOME), decks=2,
                    skill_level=SL.MOSTLY_SKILL, version='4.60')
    __author__ = 'Markus Oberhumer'
    __version__ = 7.70

    _foundation_ = stack.SS_Foundation
    _reserve_ = stack.ReserveStack

    def _start(self, rows=4, flip=True, **kw):
        """
        Deal initial cards for new game.
          - s[rows] 4 ea up.

        .. \_start([rows=4, flip=True]) -> None
        """
        super(Nomad, self)._start(rows=rows, flip=flip, **kw)


class MilliganCell(MissMilligan):
    """
    Finish cards on _foundation_ within 1 turn.

    _row_
      Pile 8 horz S _foundation_. Init deal 1 card. Build down in rank by alt
      color. Play seq. Base KING.

    _reserve_
      Pile 4 vert W. Build any 1 card. Play top.

    _talon_
      Pile 1 NW. Deal 1 card on _row_.

    _foundation_
      Pile 8 horz N. Build up in rank by same suit. Play none.
    ------
    :cvar Layout _layout_: layout.MilliganLayout
    :cvar Stack _talon_: stack.DealRowTalon
    :cvar Stack _waste_: None
    :cvar Stack _foundation_: stack.SS_Foundation (max_move=0)
    :cvar Stack _row_: stack.AC_RowStack (base_rank=KING)
    :cvar Stack _reserve_: stack.ReserveStack
    :cvar Hint _hint_: hint.DefaultHint
    """
    __info__ = dict(id=78, name='Milligan Cell', game_type=GT.GYPSY, decks=2,
                    skill_level=SL.MOSTLY_SKILL, version='3.00')
    __author__ = 'Markus Oberhumer'
    __version__ = 7.70

    _reserve_ = stack.ReserveStack

    def _create_game(self, **kw):
        kw.setdefault('reserves', 4)
        return super(MilliganCell, self)._create_game(**kw)


class MilliganHarp(Gypsy):
    """
    Finish cards on _foundation_ within 1 turn.

    _row_
      Pile 8 horz N. Init deal [1..8] card. Build down in rank by alt
      color. Play seq.

    _talon_
      Pile 1 SE. Deal 1 card on _row_.

    _foundation_
      Pile 8 horz S. Build up in rank by same suit. Play none.
    ------
    :cvar Layout _layout_: layout.HarpLayout
    :cvar Stack _talon_: stack.DealRowTalon
    :cvar Stack _waste_: None
    :cvar Stack _foundation_: stack.SS_Foundation (max_move=0)
    :cvar Stack _row_: stack.AC_RowStack
    :cvar Hint _hint_: hint.DefaultHint
    """
    __info__ = dict(id=217, name='Milligan Harp', game_type=GT.GYPSY, decks=2,
                    skill_level=SL.BALANCED, version='4.60')
    __author__ = 'Markus Oberhumer'
    __version__ = 7.70

    _layout_ = layout.HarpLayout
    _foundation_ = Wrap(stack.SS_Foundation, max_move=0)

    def _start(self, flip=False, **kw):
        """
        Deal initial cards for new game.
          - s[rows] 1..LEN top.

        .. \_start([flip=False]) -> None
        """
        for i in range(1, len(self.s['rows'])):
            self.s['talon'].dealRow(rows=self.s['rows'][i:], flip=flip,
                                    frames=0)
        self.s['talon'].dealRow()


class Carlton(MilliganHarp):
    """
    Finish cards on _foundation_ within 1 turn.

    _row_
      Pile 8 horz N. Init deal [1..8] open card. Build down in rank by alt
      color. Play seq.

    _talon_
      Pile 1 SE. Deal 1 card on _row_.

    _foundation_
      Pile 8 horz S. Build up in rank by same suit. Play none.
    ------
    :cvar Layout _layout_: layout.HarpLayout
    :cvar Stack _talon_: stack.DealRowTalon
    :cvar Stack _waste_: None
    :cvar Stack _foundation_: stack.SS_Foundation (max_move=0)
    :cvar Stack _row_: stack.AC_RowStack
    :cvar Hint _hint_: hint.DefaultHint
    """
    __info__ = dict(id=218, name='Carlton', game_type=GT.GYPSY, decks=2,
                    skill_level=SL.MOSTLY_SKILL, version='4.60')
    __author__ = 'Markus Oberhumer'
    __version__ = 7.70

    def _start(self, flip=True, **kw):
        """
        Deal initial cards for new game.
          - s[rows] 1..LEN up.

        .. \_start([flip=True]) -> None
        """
        super(Carlton, self)._start(flip=flip, **kw)


class Steve(Carlton):
    """
    Finish cards on _foundation_ within 1 turn.

    _row_
      Pile 8 horz N. Init deal [1..8] open card. Build down by rank alone.
      Play seq in rank by same suit.

    _talon_
      Pile 1 SE. Deal 1 card on _row_.

    _foundation_
      Pile 8 horz S. Build up in rank by same suit. Play none.
    ------
    :cvar Layout _layout_: layout.HarpLayout
    :cvar Stack _talon_: stack.DealRowTalon
    :cvar Stack _waste_: None
    :cvar Stack _foundation_: stack.SS_Foundation (max_move=0)
    :cvar Stack _row_: stack.AC_RowStack
    :cvar Hint _hint_: hint.DefaultHint
    """
    __info__ = dict(id=498, name='Steve', game_type=GT.GYPSY, decks=2,
                    skill_level=SL.BALANCED, version='0.93fc')
    __author__ = 'Skomoroh'
    __version__ = 7.70

    _row_ = spider.SS_RK_RowStack
    _hint_ = spider.Hint

    _quickplay_ = quickplay.Spider


class LexingtonHarp(MilliganHarp):
    """
    Finish cards on _foundation_ within 1 turn.

    :CVariables:
      _layout_ : pysollib.layout.Layout
        .. pysollib.layouts.gypsy.GypsyLayout
        - row [8 horz NW, vert offset]
        - talon [1 SE, no offset]
        - foundation [8 over 2 col E, no offset]

    _row_
      Init deal [1..8] card. Build down in rank by alt
      color. Play any.

    _talon_
      Deal 1 card on _row_.

    _foundation_
      Build up in rank by same suit. Play none.

    note::
      ⟪highlight_play⟫ disabled
    ------
    :cvar Stack _talon_: stack.DealRowTalon
    :cvar Stack _waste_: None
    :cvar Stack _foundation_: stack.SS_Foundation (max_move=0)
    :cvar Stack _row_: yukon.AC_RowStack
    :cvar Hint _hint_: yukon.Hint
    """
    __info__ = dict(id=68, name='Lexington Harp', game_type=GT.YUKON, decks=2,
                    skill_level=SL.BALANCED, version='3.00')
    __author__ = 'Markus Oberhumer'
    __version__ = 7.70

    _row_ = yukon.AC_RowStack
    _hint_ = yukon.Hint

    @property
    def _highlight_piles(self):
        """
        Get stacks to highlight for possible move.

        :return: empty.
        :rtype: tuple
        """
        return ()


class Brunswick(LexingtonHarp):
    """
    Finish cards on _foundation_ within 1 turn.

    :CVariables:
      _layout_ : pysollib.layout.Layout
        .. pysollib.layouts.gypsy.GypsyLayout
        - row [8 horz NW, vert offset]
        - talon [1 SE, no offset]
        - foundation [8 over 2 col E, no offset]

    _row_
      Init deal [1..8] open card. Build down in rank by alt
      color. Play any.

    _talon_
      Deal 1 card on _row_.

    _foundation_
      Build up in rank by same suit. Play none.

    note::
      ⟪highlight_play⟫ disabled
    ------
    :cvar Stack _talon_: stack.DealRowTalon
    :cvar Stack _waste_: None
    :cvar Stack _foundation_: stack.SS_Foundation (max_move=0)
    :cvar Stack _row_: yukon.AC_RowStack
    :cvar Hint _hint_: yukon.Hint
    """
    __info__ = dict(id=154, name='Brunswick', game_type=GT.YUKON, decks=2,
                    skill_level=SL.BALANCED, version='3.40')
    __author__ = 'Markus Oberhumer'
    __version__ = 7.70

    def _start(self, flip=True, **kw):
        """
        Deal initial cards for new game.
          - s[rows] 1..LEN up.

        .. \_start([flip=True]) -> None
        """
        super(Brunswick, self)._start(flip=flip, **kw)


class Mississippi(LexingtonHarp):
    """
    Finish cards on _foundation_ within 1 turn.

    :CVariables:
      _layout_ : pysollib.layout.Layout
        .. pysollib.layouts.gypsy.GypsyLayout
        - row [7 horz NW, vert offset]
        - talon [1 SE, no offset]
        - foundation [8 over 2 col E, no offset]

    _row_
      Init deal [1..7] card. Build down in rank by alt
      color. Play any.

    _talon_
      Deal 1 card on _row_.

    _foundation_
      Build up in rank by same suit. Play none.

    note::
      ⟪highlight_play⟫ disabled
    ------
    :cvar Stack _talon_: stack.DealRowTalon
    :cvar Stack _waste_: None
    :cvar Stack _foundation_: stack.SS_Foundation (max_move=0)
    :cvar Stack _row_: yukon.AC_RowStack
    :cvar Hint _hint_: yukon.Hint
    """
    __info__ = dict(id=121, name='Mississippi', game_type=(GT.YUKON |
                    GT.XORIGINAL), decks=2,
                    skill_level=SL.MOSTLY_SKILL, version='3.10')
    __author__ = 'Markus Oberhumer'
    __version__ = 7.70

    def _create_game(self, **kw):
        """
        Deal initial cards for new game.
          - s[rows] 1..LEN top.

        .. \_start([flip=False]) -> None
        """
        return super(Mississippi, self)._create_game(**kw)


class Griffon(Mississippi):
    """
    Finish cards on _foundation_ within 1 turn.

    :CVariables:
      _layout_ : pysollib.layout.Layout
        .. pysollib.layouts.gypsy.GypsyLayout
        - row [7 horz NW, vert offset]
        - talon [1 SE, no offset]
        - foundation [8 over 2 col E, no offset]

    _row_
      Init deal [1..7] open card. Build down in rank by alt
      color. Play any.

    _talon_
      Deal 1 card on _row_.

    _foundation_
      Build up in rank by same suit. Play none.

    note::
      ⟪highlight_play⟫ disabled
    ------
    :cvar Stack _talon_: stack.DealRowTalon
    :cvar Stack _waste_: None
    :cvar Stack _foundation_: stack.SS_Foundation (max_move=0)
    :cvar Stack _row_: yukon.AC_RowStack
    :cvar Hint _hint_: yukon.Hint
    """
    __info__ = dict(id=122, name='Griffon', game_type=(GT.YUKON |
                    GT.XORIGINAL), decks=2,
                    skill_level=SL.MOSTLY_SKILL, version='3.10')
    __author__ = 'Markus Oberhumer'
    __version__ = 7.70

    def _start(self, flip=True, **kw):
        """
        Deal initial cards for new game.
          - s[rows]  1..LEN up.

        .. \_start([flip=True]) -> None
        """
        super(Griffon, self)._start(flip=flip, **kw)


class Blockade(Gypsy):
    """
    Finish cards on _foundation_ within 1 turn.

    _row_
      Pile 12 horz N. Init deal 1 card. Build down in rank by same suit. Play
      seq. Gap deal 1 card from _talon_

    _talon_
      Pile 1 SE. Deal 1 card on _row_.

    _foundation_
      Pile 8 horz S. Build up in rank by same suit. Play none.

    seealso::
      http://en.wikipedia.org/wiki/Blockade_%28solitaire%29
    ------
    :cvar Layout _layout_:layout.KlondikeLayout
    :cvar Stack _talon_: stack.DealRowTalon
    :cvar Stack _waste_: None
    :cvar Stack _foundation_: stack.SS_Foundation
    :cvar Stack _row_: stack.SS_RowStack
    :cvar Hint _hint_: hint.DefaultHint
    """
    __info__ = dict(id=226, name='Blockade', game_type=GT.GYPSY, decks=2,
                    skill_level=SL.BALANCED, version='4.60')
    __author__ = 'Markus Oberhumer'
    __version__ = 7.70

    _layout_ = layout.KlondikeLayout
    _row_ = stack.SS_RowStack

    def _create_game(self, **kw):
        kw.setdefault('rows', 12)
        return super(Blockade, self)._create_game(**kw)

    def _start(self, rows=1, **kw):
        """
        Deal initial cards for new game.
          - s[rows] 1 ea.

        .. \_start([rows=1, flip=False]) -> None
        """
        return super(Blockade, self)._create_game(rows=rows, **kw)

    @state.move_state('fill')
    def _auto_fill(self, stack):
        """
        Fill stack if _row_ when gap from _talon_.

        *Parameters*:
           stack : Stack
             pile just played
        """
        fill.fromTalon(self, stack, self.s['rows'])


class PhantomBlockade(Gypsy):
    """
    Finish cards on _foundation_ within 1 turn.

    _row_
      Pile 12 horz N. Init deal 1 card. Build down in rank by same suit. Play
      seq. Gap deal 1 card from _talon_

    _talon_
      Pile 1 SE. Deal 1 card on _row_.

    _foundation_
      Pile 8 horz S. Build up in rank by same suit. Play none.
    ------
    :cvar Layout _layout_:layout.KlondikeLayout
    :cvar Stack _talon_: stack.DealRowTalon
    :cvar Stack _waste_: None
    :cvar Stack _foundation_: stack.SS_Foundation
    :cvar Stack _row_: stack.AC_RowStack (base_rank=KING)
    :cvar Hint _hint_: hint.DefaultHint
    """
    __info__ = dict(id=469, name='Phantom Blockade', game_type=GT.GYPSY,
                    decks=2, skill_level=SL.MOSTLY_SKILL,
                    version='0.93fc')
    __author__ = 'Skomoroh'
    __version__ = 7.70

    _layout_ = layout.KlondikeLayout
    _row_ = Wrap(stack.AC_RowStack, base_rank=cs.KING)

    def _create_game(self, **kw):
        kwdefault(kw, rows=13, playcards=24)
        return super(PhantomBlockade, self)._create_game(**kw)


class Cone(Irmgard):
    """
    Finish cards on _foundation_ within 1 turn.

    _row_
      Pile 8 horz N. Init deal [1..4..1] card. Build down in rank by alt color
      wrap. Play seq.

    _reserve_
      Pile 4 vert W. Build none. Play top.

    _talon_
      Pile 1 NW. Deal 1 card on _row_. Last deal 1 card on _reserve_.

    _foundation_
      Pile 4 vert E. Build up in rank by same suit wrap. Play top.
    ------
    :cvar Stack _talon_: Cone_Talon
    :cvar Stack _waste_: None
    :cvar Stack _foundation_: stack.SS_Foundation (mod=13, max_cards=26)
    :cvar Stack _row_: stack.AC_RowStack (mod=13)
    :cvar Stack _reserve_: stack.OpenStack
    :cvar Hint _hint_: hint.DefaultHint
    """
    __info__ = dict(id=412, name='Cone', game_type=GT.GYPSY, decks=2,
                    skill_level=SL.BALANCED, version='0.90fc')
    __author__ = 'Skomoroh'
    __version__ = 7.70

    _layout_ = GypsyLayout.SlyFoxLayout
    _talon_ = Cone_Talon
    _foundation_ = Wrap(stack.SS_Foundation, mod=13,
                                max_cards=26)
    _row_ = Wrap(stack.AC_RowStack, mod=13)
    _reserve_ = stack.OpenStack

    def _create_game(self, **kw):
        l = self._layout_(self)
        kwdefault(kw, rows=7, reserves=4, align=layout.LEFT, bases=l.SUIT)
        return super(Cone, self)._create_game(**kw)

    def _start(self, flip=True, **kw):
        """
        Deal initial cards for new game.
          - s[rows] 1..lEN//2..1 up.

        .. \_start([flip=True]) -> None
        """
        super(Cone, self)._start(flip=flip, **kw)


class Surprise(Irmgard):
    """
    Finish cards on _foundation_ within 1 turn.

    _row_
      Pile 11 horz S _foundation_. Init deal [1..6..1] card. Build down in
      rank by alt color. Play seq. Base KING.

    _reserve_
      Pile 1 E _talon_. Build any 3 cards after _talon_ gap. Play top.

    _talon_
      Pile 1 NW. Deal 1 card on _row_.

    _foundation_
      Pile 8 horz N. Build up in rank by same suit. Play top.
    ------
    :cvar Layout _layout_:layout.KlondikeLayout
    :cvar Stack _talon_: stack.DealRowTalon
    :cvar Stack _waste_: None
    :cvar Stack _foundation_: stack.SS_Foundation
    :cvar Stack _row_: stack.AC_RowStack (base_rank=KING)
    :cvar Stack _reserve_: Surprise_ReserveStack (max_cards=3)
    :cvar Hint _hint_: hint.DefaultHint
    """
    __info__ = dict(id=463, name='Surprise', game_type=GT.GYPSY, decks=2,
                    skill_level=SL.BALANCED, version='0.92fc')
    __author__ = 'Skomoroh'
    __version__ = 7.70

    _layout_ = layout.KlondikeLayout
    _talon_ = stack.DealRowTalon
    _row_ = Wrap(stack.AC_RowStack, base_rank=cs.KING)
    _reserve_ = Wrap(Surprise_ReserveStack, max_cards=3)

    def _create_game(self, **kw):
        l, s = self._layout_(self), self.s
        kwdefault(kw, rows=11, playcards=12, texts=True)
        l.create(**kw)
        self.table_size = l.size
        s['talon'] = self._talon_(l.s['talon'].x, l.s['talon'].y, game=self)
        s['reserve'].append(self._reserve_(l.s['wastes'][-1].x,
                                           l.s['wastes'][-1].y, game=self))
        for r in l.s['foundations']:
            s['foundations'].append(self._foundation_(r.x, r.y, game=self,
                                                   suit=r.suit))
        for r in l.s['rows']:
            s['rows'].append(self._row_(r.x, r.y, game=self))
        l.defaultAll()
        return l


class Elba(Gypsy):
    """
    Finish cards on _foundation_ within 1 turn.

    _row_
      Pile 10 horz S _foundation_. Init deal 5 card. Build down in rank by alt
      color. Play seq. Base KING.

    _talon_
      Pile 1 NW. Deal 1 card on _row_.

    _foundation_
      Pile 8 horz N. Build up in rank by same suit. Play top.
    ------
    :cvar Layout _layout_:layout.KlondikeLayout
    :cvar Stack _talon_: stack.DealRowTalon
    :cvar Stack _waste_: None
    :cvar Stack _foundation_: stack.SS_Foundation
    :cvar Stack _row_: stack.AC_RowStack (base_rank=KING)
    :cvar Hint _hint_: hint.DefaultHint
    """
    __info__ = dict(id=478, name='Elba', game_type=GT.GYPSY, decks=2,
                    skill_level=SL.MOSTLY_SKILL, version='0.93fc')
    __author__ = 'Skomoroh'
    __version__ = 7.70

    _layout_ = layout.KlondikeLayout
    _row_ = Wrap(stack.AC_RowStack, base_rank=cs.KING)

    def _create_game(self, **kw):
        kw.setdefault('rows', 10)
        return super(Elba, self)._create_game(**kw)

    def _start(self, rows=5, **kw):
        """
        Deal initial cards for new game.
          - s[rows] 5 ea up.

        .. \_start([rows=5, flip=False]) -> None
        """
        super(Elba, self)._start(rows=5, **kw)


class Millie(Gypsy):
    """
    Finish cards on _foundation_ within 1 turn.

    :CVariables:
      _layout_ : pysollib.layout.Layout
        .. pysollib.layouts.klondike.KlondikeLayout
        - row [8 horz S foundation, vert offset]
        - talon [1 NW, no offset]
        - foundation [8 horz N, no offset]

    _row_
      Init deal 1 card. Build down in rank by alt
      color. Play seq.

    _talon_
      Deal 1 card on _row_.

    _foundation_
      Build up in rank by same suit. Play top.
    ------
    :cvar Stack _talon_: stack.DealRowTalon
    :cvar Stack _waste_: None
    :cvar Stack _foundation_: stack.SS_Foundation
    :cvar Stack _row_: stack.AC_RowStack
    :cvar Hint _hint_: hint.DefaultHint
    """
    __info__ = dict(id=487, name='Millie', game_type=GT.GYPSY, decks=2,
                    skill_level=SL.BALANCED, version='0.93fc')
    __author__ = 'Skomoroh'
    __version__ = 7.70

    _layout_ = KlondikeLayout.KlondikeLayout

    def _create_game(self, **kw):
        kw.setdefault('playcards', 24)
        return super(Millie, self)._create_game(**kw)

    def _start(self, rows=1, **kw):
        """
        Deal initial cards for new game.
          - s[rows] 1 ea up.

        .. \_start([rows=1, flip=False]) -> None
        """
        super(Millie, self)._start(rows=rows, **kw)


class Eclipse(Millie):
    """
    Finish cards on _foundation_ within 1 turn.

    :CVariables:
      _layout_ : pysollib.layout.Layout
        .. pysollib.layouts.fortythieves.FortyThievesLayout
        - row [13 horz S foundation, vert offset]
        - talon [1 SE, no offset]
        - foundation [8 horz N, no offset]

    _row_
      Init deal 4 card. Build down in rank by
      same suit. Play seq.

    _talon_
      Deal 1 card on _row_.

    _foundation_
      Build up in rank by same suit. Play top.
    ------
    :cvar Stack _talon_: stack.DealRowTalon
    :cvar Stack _waste_: None
    :cvar Stack _foundation_: stack.SS_Foundation
    :cvar Stack _row_: stack.SS_RowStack
    :cvar Hint _hint_: hint.DefaultHint
    """
    __info__ = dict(id=584, name='Eclipse', game_type=GT.GYPSY, decks=2,
                    skill_level=SL.MOSTLY_SKILL, version='0.93fc')
    __author__ = 'Skomoroh'
    __version__ = 7.70

    _layout_ = FortyThievesLayout.FortyThievesLayout
    _row_ = stack.SS_RowStack

    def _create_game(self, **kw):
        kw.setdefault('rows', 13)
        return super(Eclipse, self)._create_game(**kw)

    def _start(self, rows=4, **kw):
        """
        Deal initial cards for new game.
          - s[rows] 4 ea up.

        .. \_start([rows=4, flip=True]) -> None
        """
        super(Eclipse, self)._start(rows=rows, **kw)


class Hypotenuse(Millie):
    """
    Finish cards on _foundation_ within 1 turn.

    _row_
      Pile 10 horz S _foundation_. Init deal [10..1] card. Build down in rank
      by alt color. Play seq. Base KING.

    _talon_
      Pile 1 NW. Deal 1 card on _row_.

    _foundation_
      Pile 8 horz N. Build up in rank by same suit. Play top.
    ------
    :cvar Layout _layout_:layout.KlondikeLayout
    :cvar Stack _talon_: stack.DealRowTalon
    :cvar Stack _waste_: None
    :cvar Stack _foundation_: stack.SS_Foundation
    :cvar Stack _row_: stack.AC_RowStack (base_rank=KING)
    :cvar Hint _hint_: hint.DefaultHint
    """
    __info__ = dict(id=566, name='Hypotenuse', game_type=GT.GYPSY, decks=2,
                    skill_level=SL.MOSTLY_SKILL, version='0.93fc')
    __author__ = 'Skomoroh'
    __version__ = 7.70

    _row_ = Wrap(stack.AC_RowStack, base_rank=cs.KING)

    def _create_game(self, **kw):
        kw.setdefault('rows', 10)
        return super(Hypotenuse, self)._create_game(**kw)

    def _start(self, flip=False, reverse=True, **kw):
        """
        Deal initial cards for new game.
          - s[rows] LEN..1 top. reverse.

        .. \_start([flip=False, reverse=True]) -> None
        """
        for i in range(1, len(self.s['rows'])):
            self.s['talon'].dealRow(rows=self.s['rows'][:i], frames=0,
                                    flip=flip, reverse=reverse)
        self.s['talon'].dealRow(reverse=reverse)


class EternalTriangle(Hypotenuse):
    """
    Finish cards on _foundation_ within 1 turn.

    _row_
      Pile 10 horz S _foundation_. Init deal [1..10] card. Build down in rank
      by alt color. Play seq. Base KING.

    _talon_
      Pile 1 NW. Deal 1 card on _row_.

    _foundation_
      Pile 8 horz N. Build up in rank by same suit. Play top.
    ------
    :cvar Layout _layout_:layout.KlondikeLayout
    :cvar Stack _talon_: stack.DealRowTalon
    :cvar Stack _waste_: None
    :cvar Stack _foundation_: stack.SS_Foundation
    :cvar Stack _row_: stack.AC_RowStack (base_rank=KING)
    :cvar Hint _hint_: hint.DefaultHint
    """
    __info__ = dict(id=567, name='Eternal Triangle', game_type=GT.GYPSY,
                    decks=2, skill_level=SL.MOSTLY_SKILL,
                    altnames=('Lobachevsky',), version='0.93fc')
    __author__ = 'Skomoroh'
    __version__ = 7.70

    def _start(self, flip=False, reverse=True, **kw):
        """
        Deal initial cards for new game.
          - s[rows] 1..LEN top. reverse.

        .. \_start([flip=False, reverse=True]) -> None
        """
        for i in range(1, len(self.s['rows'])):
            self.s['talon'].dealRow(rows=self.s['rows'][i:], frames=0,
                                    flip=flip, reverse=reverse)
        self.s['talon'].dealRow(reverse=reverse)


class BrazilianPatience(EternalTriangle):
    """
    Finish cards on _foundation_ within 1 turn.

    _row_
      Pile 10 horz S _foundation_. Init deal [1..10] card. Build down in rank
      by alt color. Play seq. Base KING.

    _talon_
      Pile 1 NW. Deal 1 card on _row_.

    _foundation_
      Pile 8 horz N. Build up in rank by same suit. Play top.
    ------
    :cvar Layout _layout_:layout.KlondikeLayout
    :cvar Stack _talon_: stack.DealRowTalon
    :cvar Stack _waste_: None
    :cvar Stack _foundation_: stack.SS_Foundation
    :cvar Stack _row_: stack.AC_RowStack (base_rank=KING)
    :cvar Hint _hint_: hint.DefaultHint
    """
    __info__ = dict(id=640, name='Brazilian Patience', game_type=GT.GYPSY,
                    decks=2, skill_level=SL.MOSTLY_SKILL,
                    version='0.93fc')
    __author__ = 'Skomoroh'
    __version__ = 7.70

    def _start(self, reverse=False, **kw):
        """
        Deal initial cards for new game.
          - s[rows] 1..LEN top.

        .. \_start([flip=False, reverse=False]) -> None
        """
        super(BrazilianPatience, self)._start(reverse=reverse, **kw)


class RightTriangle(Hypotenuse):
    """
    Finish cards on _foundation_ within 1 turn.

    _row_
      Pile 10 horz S _foundation_. Init deal [1..10] card. Build down in rank
      by alt color. Play seq. Base KING.

    _talon_
      Pile 1 NW. Deal 1 card on _row_. Build none. Play top.

    _foundation_
      Pile 8 horz N. Build up in rank by same suit. Play top.
    ------
    :cvar Layout _layout_:layout.KlondikeLayout
    :cvar Stack _talon_: RightTriangle_Talon
    :cvar Stack _waste_: None
    :cvar Stack _foundation_: stack.SS_Foundation
    :cvar Stack _row_: stack.AC_RowStack (base_rank=KING)
    :cvar Hint _hint_: hint.DefaultHint
    """
    __info__ = dict(id=568, name='Right Triangle', game_type=GT.GYPSY,
                    decks=2, skill_level=SL.MOSTLY_SKILL,
                    version='0.93fc')
    __author__ = 'Skomoroh'
    __version__ = 7.70

    _talon_ = RightTriangle_Talon

    def _create_game(self, **kw):
        l = super(RightTriangle, self)._create_game(**kw)
        self.sg['dropstacks'] += [self.s['talon']]
        self.sg['openstacks'] += [self.s['talon']]
        self.sg['reservestacks'] += [self.s['talon']]
        return l


class Trapdoor(Gypsy):
    """
    Finish cards on _foundation_ within 1 turn.

    :CVariables:
      _layout_ : pysollib.layout.Layout
        .. pysollib.layouts.gypsy.GypsyLayout
        - row [8 horz NW, vert offset]
        - talon [1 SE, no offset]
        - foundation [8 over 2 col E, no offset]
        - reserve [8 SW, no offset]

    _row_
      Init deal 3 card. Build down in rank by alt color. Play
      seq.

    _reserve_
      Init deal 1 card. Build none. Play top.

    _talon_
      Play _reserve_ with cards on neighbor _row_ then deal 1 card
      on _reserve_.

    _foundation_
      Build up in rank by same suit. Play top.
    ------
    :cvar Stack _talon_: Trapdoor_Talon
    :cvar Stack _waste_: None
    :cvar Stack _foundation_: stack.SS_Foundation
    :cvar Stack _row_: stack.AC_RowStack
    :cvar Stack _reserve_: stack.OpenStack
    :cvar Hint _hint_: hint.DefaultHint
    """
    __info__ = dict(id=580, name='Trapdoor', game_type=(GT.GYPSY |
                    GT.ORIGINAL), decks=2, version='0.93fc',
                    skill_level=SL.MOSTLY_SKILL)
    __author__ = 'Skomoroh'
    __version__ = 7.70

    _talon_ = Trapdoor_Talon
    _reserve_ = stack.OpenStack

    def _create_game(self, **kw):
        kw.setdefault('reserves', 8)
        return super(Trapdoor, self)._create_game(**kw)

    def _start(self, **kw):
        """
        Deal initial cards for new game.
          - s[rows] 3 ea top.
          - talon deal.

        .. \_start([rows=5, flip=False]) -> None
        """
        super(Trapdoor, self)._start(self, **kw)
        self.talon_deal(sound=False)


class TrapdoorSpider(Trapdoor):
    """
    Finish cards on _foundation_ within 1 turn.

    :CVariables:
      _layout_ : pysollib.layout.Layout
        .. pysollib.layouts.gypsy.GypsyLayout
        - row [10 horz NW, vert offset]
        - talon [1 SE, no offset]
        - foundation [8 over 2 col E, no offset]
        - reserve [10 SW, no offset]

    _row_
      Init deal [5, 4, 4, 5, 4, 4, 5, 4, 4, 5] card. Build
      down in rank alone. Play seq in rank by same suit. Drop full seq on
      _foundations_

    _reserve_
      Init deal 1 card. Build none. Play top.

    _talon_
      Play _reserve_ with cards on neighbor _row_ then deal 1 card
      on _reserve_.

    _foundation_
      Build none. Play none.
    ------
    :cvar Stack _talon_: Trapdoor_Talon
    :cvar Stack _waste_: None
    :cvar Stack _foundation_: spider.SS_Foundation
    :cvar Stack _row_: spider.Drop_SS_RK_RowStack
    :cvar Stack _reserve_: stack.OpenStack
    :cvar Hint _hint_: spider.Hint
    """
    __info__ = dict(id=666, name='Trapdoor Spider', game_type=(GT.SPIDER |
                    GT.ORIGINAL), decks=2, version='0.94fc',
                    skill_level=SL.MOSTLY_SKILL)
    __author__ = 'Skomoroh'
    __version__ = 7.70

    _foundation_ = spider.SS_Foundation
    _row_ = spider.DropSS_RK_RowStack
    _hint_ = spider.Hint

    def _create_game(self, **kw):
        kwdefault(kw, rows=10, reserves=10)
        return super(TrapdoorSpider, self)._create_game(**kw)

    def _start(self, rows=5, flip=False):
        """
        Deal initial cards for new game.
          - s[rows] 3 ea up.
          - s[rows][0::3] 1 ea.
          - s[rows] 1 ea.
          - talon deal.

        .. \_start([rows=5, flip=True]) -> None
        """
        for i in range(rows - 2):
            self.s['talon'].dealRow(flip=flip, frames=0)
        self.s['talon'].dealRow(rows=self.s['rows'][0::3], flip=flip, frames=0)
        self.s['talon'].dealRow()
        self.talon_deal(sound=False)

    _quickplay_ = quickplay.Spider


class Flamenco(Gypsy):
    """
    Finish cards on _foundation_ within 1 turn.

    :CVariables:
      _layout_ : pysollib.layout.Layout
        .. pysollib.layouts.gypsy.GypsyLayout
        - row [8 horz NW, vert offset]
        - talon [1 SE, no offset]
        - foundation [8 over 2 col E, no offset]

    _row_
      Init deal 3 card. Build down in rank by alt color. Play
      seq.

    _talon_
      Deal 1 card on _row_.

    _foundation_
      Init deal E base ACE and W base KING. Build in rank
      by same suit. W up. W down. Play top.
    ------
    :cvar Stack _talon_: stack.DealRowTalon
    :cvar Stack _waste_: None
    :cvar Stack _foundation_: stack.SS_Foundation
    :cvar Stack _row_: stack.AC_RowStack
    :cvar Hint _hint_: hint.DefaultHint
    """
    __info__ = dict(id=581, name='Flamenco', game_type=(GT.GYPSY |
                    GT.ORIGINAL), decks=2,
                    skill_level=SL.MOSTLY_SKILL, version='0.93fc')
    __author__ = 'Skomoroh'
    __version__ = 7.70

    _foundations_ = (stack.SS_Foundation,
                     Wrap(stack.SS_Foundation, base_rank=cs.KING, dir=-1),)

    def _create_game(self, **kw):
        kwdefault(kw, rows=8, texts=True)
        return super(Flamenco, self)._create_game(**kw)

    def _pack_place(self, cards):
        """
        _pack_place(cards:seq(Card ...)) -> seq(Card ...)

        Overide to return ACE and KING of suit on top by rank, suit, deck for
        _foundation_ deal.
        """
        return place.MoveToTop(cards, place.OneAceKing)

    def _start(self, **kw):
        """
        Deal initial cards for new game.
          - s[foundations] 1 ea.
          - s[rows] 3 ea up.

        .. \_start([rows=3, flip=False]) -> None
        """
        self.s['talon'].dealRow(rows=self.s['foundations'], frames=0)
        super(Flamenco, self)._start(**kw)


class Leprechaun(Gypsy):
    """
    Finish cards on _foundation_ within 1 turn.

    _row_
      Pile 8 horz S _foundation_. Init deal 3 card. Build down in rank by alt
      color. Play seq.

    _reserve_
      Pile 8 horz N. Init deal 4 close card. Build none. Play top. Flip after
      neighbor _foundation_ has cards.

    _talon_
      Pile 1 NW. Deal 1 card on _row_.

    _foundation_
      Pile 8 horz S _reserve. Build up in rank by same suit. Play top.
    ------
    :cvar Layout _layout_: layout.LeprechaunLayout
    :cvar Stack _talon_: stack.DealRowTalon
    :cvar Stack _foundation_: stack.SS_Foundation
    :cvar Stack _row_: stack.AC_RowStack
    :cvar Stack _reserve_: Leprechaun_Reserve
    :cvar Hint _hint_: hint.DefaultHint
    """
    __info__ = dict(id=712, name='Leprechaun', game_type=(GT.GYPSY |
                    GT.ORIGINAL), decks=2,
                    skill_level=SL.MOSTLY_SKILL, version='1.10fc')
    __author__ = 'Skomoroh'
    __version__ = 7.70

    _layout_ = layout.LeprechaunLayout
    _talon_ = stack.DealRowTalon
    _foundation_ = stack.SS_Foundation
    _row_ = stack.AC_RowStack
    _reserve_ = Leprechaun_Reserve

    def _create_game(self, **kw):
        kwdefault(kw, rows=8, reserves=8, playcards=12)
        return super(Leprechaun, self)._create_game(**kw)

    def _start(self, reserves=4, **kw):
        """
        Deal initial cards for new game.
          - s[reserves] 4
          - s[rows] 3 ea top.

        .. \_start([rows=3, flip=False, reserves=4]) -> None
        """
        kwdefault(kw, rows=3, flip=False)
        for i in range(reserves):
            self.s['talon'].dealRow(rows=self.s['reserves'], flip=False,
                                    frames=0)
        super(Leprechaun, self)._start(**kw)


class LockedCards(Leprechaun):
    """
    Finish cards on _foundation_ within 3 turn.

    _row_
      Pile 8 horz S _foundation_. Init deal 5 card. Build down in rank by alt
      color. Play seq.

    _reserve_
      Pile 7 horz N. Init deal 1 close card. Build none. Play top. Flip after
      neighbor _foundation_ is full.

    _talon_
      Pile 1 SW. Deal 1 card on _row_.

    _waste_
      Pile 1 SW. Init deal 1 card. Deal 1 card on _row_.

    _foundation_
      Pile 8 horz S _reserve. Build up in rank by same suit. Play none. Base
      any suit.
    ------
    :cvar Layout _layout_: layout.LeprechaunLayout
    :cvar Stack _talon_: stack.WasteTalon (max_rounds=3)
    :cvar Stack _waste_: stack.WasteStack
    :cvar Stack _foundation_: stack.SS_Foundation (suit=ANY, max_move=0)
    :cvar Stack _row_: stack.AC_RowStack
    :cvar Stack _reserve_: LockedCards_Reserve
    :cvar Hint _hint_: hint.DefaultHint
    """
    __info__ = dict(id=718, name='Locked Cards', game_type=GT.TWO_DECK,
                    decks=2, redeals=2, skill_level=SL.BALANCED,
                    version='1.10fc')
    __author__ = 'Skomoroh'
    __version__ = 7.70

    _talon_ = Wrap(stack.WasteTalon, max_rounds=3)
    _waste_ = stack.WasteStack
    _foundation_ = Wrap(LockedCards_Foundation, suit=cs.ANY, max_move=0)
    _row_ = stack.AC_RowStack
    _reserve_ = LockedCards_Reserve

    def _create_game(self, **kw):
        kwdefault(kw, rows=8, reserves=7, playcards=14)
        return super(LockedCards, self)._create_game(**kw)

    def _start(self, rows=5, flip=True, reserves=1, **kw):
        """
        Deal initial cards for new game.
          - s[reserves] 1
          - s[rows] 5 ea up.

        .. \_start([rows=5, flip=True, reserves=1]) -> None
        """
        super(LockedCards, self)._start(rows=rows, flip=flip, reserves=reserves,
                                        **kw)


class TopsyTurvyQueens(LockedCards):
    """
    Finish cards on _foundation_ within 3 turn.

    _row_
      Pile 8 horz S _foundation_. Init deal 4 card. Build down in rank by alt
      color wrap. Play seq.

    _reserve_
      Pile 7 horz N. Init deal 1 close card. Build none. Play top. Flip after
      neighbor _foundation_ is full.

    _talon_
      Pile 1 SW. Deal 1 card on _row_.

    _waste_
      Pile 1 SW. Init deal 1 card. Deal 1 card on _row_.

    _foundation_
      Pile 8 horz S _reserve. Build up in rank by same suit wrap from base
      KING. Play none. Base any suit.
    ------
    :cvar Layout _layout_: layout.LeprechaunLayout
    :cvar Stack _talon_: stack.WasteTalon (max_rounds=3)
    :cvar Stack _waste_: stack.WasteStack
    :cvar Stack _foundation_: stack.SS_Foundation (suit=ANY, max_move=0)
    :cvar Stack _row_: stack.AC_RowStack (mod=13)
    :cvar Stack _reserve_: LockedCards_Reserve
    :cvar Hint _hint_: hint.DefaultHint
    """
    __info__ = dict(id=725, name='Topsy-Turvy Queens',
                    game_type=GT.TWO_DECK, decks=2, redeals=2,
                    skill_level=SL.BALANCED, version='1.10fc')
    __author__ = 'Skomoroh'
    __version__ = 7.70

    _foundation_ = Wrap(LockedCards_Foundation, base_rank=cs.KING, suit=cs.ANY,
                        mod=13, max_move=0)
    _row_ = Wrap(stack.SS_RowStack, mod=13)

    def _start(self, rows=4, **kw):
        """
        Deal initial cards for new game.
          - s[reserves] 1
          - s[rows] 4 ea up.

        .. \_start([rows=4, flip=True, reserves=1]) -> None
        """
        super(TopsyTurvyQueens, self)._start(rows=rows, **kw)


class Thirty(Gypsy):
    """
    Finish cards on _foundation_ within 1 turn.

    :CVariables:
      _layout_ : pysollib.layout.Layout
        .. pysollib.layouts.freecell.FreecellLayout
        - row [6 horz S reserve and foundation, vert offset]
        - talon [1 SE, no offset]
        - foundation [8 over 2 NE, no offset]
        - reserve [2 horz NW, no offset]

    _row_
      Init deal 5 card. Build down in rank alone.
      Play seq in rank by same suit.

    _reserve_
      Init deal 1 card. Build none. Play top.

    _foundation_
      Build up in rank by same suit. Play top.
    ------
    :cvar Stack _talon_: stack.InitialDealTalon
    :cvar Stack _foundation_: DieRussische_Foundation
    :cvar Stack _row_: spider.RankSS_RK_RowStack
    :cvar Stack _reserve_: stack.Openstack
    :cvar Hint _hint_: spider.Hint
    """
    __info__ = dict(id=721, name='Thirty', game_type=(GT.SPIDER | GT.OPEN),
                    decks=1, skill_level=SL.MOSTLY_SKILL,
                    version='1.10fc', ranks=cs.SHORT_A7K)
    __author__ = 'Skomoroh'
    __version__ = 7.70

    _layout_ = FreeCellLayout.FreeCellLayout
    _talon_ = stack.InitialDealTalon
    _foundation_ = DieRussische_Foundation
    _rows_ = spider.RankSS_RK_RowStack
    _reserve_ = stack.OpenStack
    _hint_ = spider.Hint

    def _create_game(self, **kw):
        kwdefault(kw, rows=6, reserves=2, playcards=12)
        return super(Thirty, self)._create_game(**kw)

    def _start(self, rows=5, flip=True, **kw):
        """
        Deal initial cards for new game.
          - s[rows] 5 ea up.
          - s[reserves] 1

        .. \_start([rows=5, flip=True]) -> None
        """
        super(Thirty, self)._start(rows=rows, flip=flip, **kw)
        self.s['talon'].dealRow(rows=self.s['reserves'])

    _quickplay_ = quickplay.Spider


class DieBoeseSieben(Gypsy):
    """
    Finish cards on _foundation_ within 1 turn.

    :CVariables:
      _layout_ : pysollib.layout.Layout
        .. pysollib.layouts.fortythieves.FortyThievesLayout
        - row [8 horz S foundation, vert offset]
        - talon [1 SW, no offset]
        - foundation [8 horz NE, no offset]

    _row_
      Init deal 7 alt open card. Build down in
      rank by alt color. Play seq.

    _talon_
      Deal 1 card on _row_. Redeal all card alt open on _row_.

    _foundation_
      Build up in rank by same suit. Play top.
    ------
    :cvar Stack _talon_: Bad7Talon (max_rounds=2)
    :cvar Stack _foundation_: DieRussische_Foundation (max_move=0)
    :cvar Stack _row_: stack.AC_RowStack
    :cvar Hint _hint_: hint.defaultHint
    """
    __info__ = dict(id=120, name='Bad Seven', game_type=GT.GYPSY, decks=2,
                    redeals=1, skill_level=SL.MOSTLY_LUCK, ranks=cs.SHORT_A7K,
                    altnames=("Die Böse Sieben",), version='3.10')
    _layout_ = FortyThievesLayout.FortyThievesLayout
    _talon_ = Wrap(Bad7Talon, max_rounds=2)
    _foundation_ = Wrap(DieRussische_Foundation, max_move=0)
    _row_ = stack.AC_RowStack

    def _create_game(self, **kw):
        kwdefault(kw, rows=7, text=True, align=layout.LEFT)
        return super(DieBoeseSieben, self)._create_game(**kw)

    def _start(self, flips=[True, False] * 3 + [True], **kw):
        """
        Deal initial cards for new game.
          - s[rows] 7 ea alt.
          - talon deal.

        .. \_start([flips=[True, False] * 3 + [True]]) -> None
        """
        for flip in flips[:-1]:
            self.s['talon'].dealRow(flip=flip, frames=0)
        self.s['talon'].dealRow(flip=flips[-1])
        self.talon_deal(sound=False)


PROVIDES = [Gypsy, Giant, Irmgard, DieKoenigsbergerin, DieRussische,
           MissMilligan, Nomad, MilliganCell, MilliganHarp, Carlton,
           LexingtonHarp, Brunswick, Mississippi, Griffon, Blockade, Cone,
           Surprise, PhantomBlockade, Elba, ImperialGuards, Millie, Steve,
           Hypotenuse, EternalTriangle, RightTriangle, Trapdoor, Flamenco,
           Eclipse, BrazilianPatience, TrapdoorSpider, Leprechaun,
           LockedCards, Thirty, TopsyTurvyQueens, DieBoeseSieben]